package jee.boot.module.oauth2.config;

import jee.boot.common.utils.SpringContextHolder;
import jee.boot.common.utils.StringUtils;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 *
 */
public class OwnPasswordTokenGranter extends AbstractTokenGranter {
	private static final String GRANT_TYPE = "password";
	private final AuthenticationManager authenticationManager;

	public OwnPasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
		this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
	}

	protected OwnPasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
		super(tokenServices, clientDetailsService, requestFactory, grantType);
		this.authenticationManager = authenticationManager;
	}

	@Override
	protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
		UserDetailHandler userDetailHandler = SpringContextHolder.getBean(UserDetailHandler.class);

		// 获取入参用户名/密码/验证码
		Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
		String username = parameters.get("username");
		String password = parameters.get("password");
		String verCode = parameters.get("verCode");

		// 密码保护
		parameters.remove("password");
		// 验证图片验证码
		if (userDetailHandler.checkIfNeedValidateCode()){
			String pin = parameters.get("pin");
			String pinKey = parameters.get("pinKey");
			String cacheCode = userDetailHandler.checkImgCode(pinKey);
			if (cacheCode == null){
				throw new InvalidGrantException("The verification code has expired, please re-verify");
			}
			if (pin==null){
				throw new InvalidGrantException("The verification code is invalid or incorrect. Please re-acquire and verify");
			}
			if (!StringUtils.equalsIgnoreCase(pin,cacheCode)){
				throw new InvalidGrantException("The verification code is invalid or incorrect. Please re-acquire and verify");
			}
		}
		// 判断验证码逻辑
		if(!userDetailHandler.checkVerificationCode(username)) {
			if(verCode == null || verCode.length() <= 0 || "undefined".equals(verCode)) {
				throw new InvalidGrantException("The verification code has expired, please re-verify");
			} else {
				String verCodeRedis = userDetailHandler.getVerCodeRedis(username);

				// 判断验证码是否为空
				if(verCodeRedis == null || verCodeRedis.length() <= 0) {
					throw new InvalidGrantException("The verification code is invalid or incorrect. Please re-acquire and verify");
				}

				// 验证 验证码
				if(!verCodeRedis.equals(verCode)) {
					throw new InvalidGrantException("The verification code is invalid or incorrect. Please re-acquire and verify");
				}

				// 更新验证码时间信息
				userDetailHandler.updateLastVerDate(username);
			}
		}
		// 用户名不存在
		if(!userDetailHandler.checkUser(username)) {
			throw new InvalidGrantException("username or password is wrong");
//			throw new InvalidGrantException("user does not exist : " + username);
		}

		// 判断账户锁定
		if(userDetailHandler.checkLock(username)) {
			throw new InvalidGrantException("The account is locked, please contact the administrator");
		}




		// 进行验证用户名密码
		Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
		((AbstractAuthenticationToken) userAuth).setDetails(parameters);
		try {
			userAuth = authenticationManager.authenticate(userAuth);
		} catch (AccountStatusException ase) {
			throw new InvalidGrantException(ase.getMessage());
		} catch (BadCredentialsException e) {
			// 用户名密码验证失败，更新锁定次数
			Integer failCount = userDetailHandler.checkLockNumber(username);
			throw new InvalidGrantException("username or password is wrong(" + failCount + " times).The account will be locked after [" + 3 + "] incorrect password entries");
		} catch(Exception e) {
			e.printStackTrace();
			throw new InvalidGrantException("system wrong",e);
		}

		// 判断是否是初始化
		if(userDetailHandler.checkInit(username)) {
			throw new InvalidGrantException("Initialization account, please change password");
		}
		// 判断账户密码是否过期
		if(userDetailHandler.checkEffectivePassword(username)) {
			throw new InvalidGrantException("Password has been expired");
		}
		// 更新验证码锁定次数
		userDetailHandler.resetLockNumber(username);

		// 正常返回
		OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
		return new OAuth2Authentication(storedOAuth2Request, userAuth);
	}
}
